#pragma once

#include "IDSBox.h"
#include "IDSReal3D.h"

#include <list>
//#include <algorithm>

namespace IDS {
	namespace OpenGL {

		class GLCell;

		//-----------------------------------------------------------------------------------------
		class GLElement
		{
		public:
			IDSBox boundingBox;
			GLCell* cell;
		public:
			virtual IDSReal3D getCentroid()
			{
				return this->boundingBox.center();
			}

			virtual void basicDraw()
			{
			}
		};

		class GLCellCaching;

		//-----------------------------------------------------------------------------------------
		class GLCell
		{
		public:
			// Default Constructor
			GLCell(GLCell** rootPtr);

			// Constructor
			GLCell(GLCell* parent, std::list<GLElement*> elemList,
				IDSBox boundingBox, IDSReal3D barycenter);

			// Destructor
			~GLCell();

			// Reset parameters
			void reset(GLCell* parent, IDSBox boundingBox, IDSReal3D barycenter);

			// Divide cell in two (create children)
			void split();

			// Add element to cell
			void addElem(GLElement* elem);

			// Remove element from cell
			void removeElem(GLElement* elem);

			// Deletes the cell and updates the relationships between brother, parent and grandparent
			void deleteCell();

		private:
			// Internal Constructor
			GLCell(GLCell* parent);

		protected:
			GLCell** rootPtrPtr;

			// Bounding box of all the elements with the center in box
			IDSBox boundingBox;

			// Number of elements
			////int numElems;
			
			std::list<GLElement*> elementList;

			// Splitting index
			int index;
			// Barycenter of the elements in the cell
			IDSReal3D barycenter;

			// Parent Cell
			GLCell* parent;

			// Children Cells
			GLCell* children[2];

			// Extend the bounding box of the cell and all the parents
			void extendBoundingBox(const IDSBox& box);

		public:
			// Maximum number of triangles in each cell
			static int MaxNumPerCell;

			// Visualization cache
			GLCellCaching* caching;

			// Refresh
			void refresh(bool onlyColours);

			// Refresh(false) + Extend the bounding box
			void refresh(const IDSBox& box);

			friend class GLCaching;
		};


		//-----------------------------------------------------------------------------------------
		// Visualization cache
		class GLCellCaching
		{
		public:
			virtual ~GLCellCaching() { }
			virtual void draw(GLCell* cell, int level) = 0;
			virtual void refresh(bool onlyColours) = 0;
		};
	}
}

